#pragma once

#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>
#include <boost/unordered_map.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boostext/typedefs.hpp>
#include <boostext/thread/lock_ptr.hpp>

#include "exports.hpp"
#include "service.hpp"
#include "task.hpp"
#include "scheduler.hpp"




namespace services
{
	/**
	 * This class offers ways to call functions at a later point or multiple times in predefined intervals.
	 * These calls happen async. and thus must be properly synchronized.
	 */
	class SERVICES_API timer
		: public service
	{
	public:

		typedef boost::function<void()>            timer_fn;
		typedef boost::posix_time::time_duration   time_duration;
		typedef boost::posix_time::ptime           ptime;
		typedef boost::shared_ptr<byte>            handle;

	public:

		static const QString   SERVICE_NAME;

	private:

		class timer_task
		{
		private:

			timer_fn        m_function;
			time_duration   m_duration;
			ptime           m_last;

		public:

			/**
			 * Creates a new client with the given functor, duration to be called
			 * and last time it was called.
			 */
			timer_task(timer_fn function, time_duration duration, ptime last);

			/**
			 * Tests if the client should be notified or not.
			 */
			bool should_notify() const;

			/**
			 * Calls the stored function object.
			 */
			void operator()();
		};
		///////////////////////////////////////////////////////////////////////////////////////////

	private:

		typedef boost::unordered_map<handle, timer_task>   timers;
		typedef boostext::synchronized<timers>             sync_timers;
		sync_timers      m_timers;
		scheduler::ptr   m_scheduler;
		task::ptr        m_task;

	public:

		timer(boost::shared_ptr<const provider>);
		virtual ~timer();



		/**
		 * @returns the name of this service
		 */
		virtual QString name() const;

		/**
		 * @returns the list of dependencies
		 */
		virtual QStringList dependencies() const;



		/**
		 * Adds the given timer to this service.
		 * The given function will be called in the given interval, but most likely
		 * from another thread than the current one.
		 */
		handle add(timer_fn function, time_duration duration);

		/**
		 * Removes the timer, identified by the given handle.
		 */
		void remove(handle h);

	private:

		void task_run();
	};
	///////////////////////////////////////////////////////////////////////////////////////////////
}
///////////////////////////////////////////////////////////////////////////////////////////////////
